package in.jsonrpc.server;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
 * The Class JsonRpcServer.<p>
 * The server object is initialized only one time by DevServlet. And then services
 * are binded to this server object.<p>
 * When DevServlet receives a new JSON-RPC request, it forwards this request to the
 * server. The server read the request and invoke requested handler to retrieve result from
 * corresponding service. Then it responses the client with the received result.
 * 
 * @version 0.1
 * @author 7inpham@gmail.com
 */
public class JsonRpcServer {
	private static final int BUFF_LENGTH = 1024;
	private static final Pattern METHOD_PATTERN = Pattern
			.compile("([_a-zA-Z][_a-zA-Z0-9]*)\\.([_a-zA-Z][_a-zA-Z0-9]*)");
	// private int maxThreads;
	// ExecutorService exec;

	public JsonRpcServer() {
		// exec = Executors.newFixedThreadPool(4);
	}

	public void execute(HttpServletRequest req, HttpServletResponse resp) {
		JsonObject jso = null;
		String reqId = null;
		String reqService = null;
		String reqMethod = null;
		// try {
		// String reqJson = "dsa";
		// jso = new JsonParser().parse(reqJson).getAsJsonObject();
		// } catch (Exception e1) {
		// // send error code
		// }
		// try {
		// assert jso != null;
		// reqId = jso.get("id").getAsString();
		// reqService = jso.get("service").getAsString();
		// reqMethod = jso.get("method").getAsString();
		// List<Object> list = new ArrayList<Object>();
		// Iterator<JsonElement> iter =
		// jso.get("parameters").getAsJsonArray().iterator();
		// while (iter.hasNext()){
		// list.add(iter.next().getAsString());
		// }
		// reqParams = {list.toArray()};
		// } catch (Exception e2) {
		// // send error code
		// }
		// // Search compatible service and invoke it
		// try {
		// Class<?> clazz = Class.forName(reqService);
		// Method[] methods = clazz.getDeclaredMethods();
		// Method candidate = null;
		// for (Method method : methods) {
		// if (!method.getName().equals(reqMethod)) {
		// continue; // Ignore methods, which do not have the right
		// // name
		// }
		// if (!Modifier.isPublic(method.getModifiers())) {
		// continue; // Ignore methods, which aren't public
		// }
		// if (method.getParameterTypes().length != reqParams.size()) {
		// continue; // Ignore methods, which do not require the same
		// // number of parameters
		// }
		// // FIXME does not cover the case
		// // "the same name and the same number of parameters"
		// // invoke first candidate.
		// candidate = method;
		// break;
		// }
		// if (candidate == null) { // service not found
		// } else {
		// candidate.invoke(clazz.newInstance(), reqParams);
		// }
		// } catch (Exception e) {
		// }
	}

	private String readRequest(HttpServletRequest req) throws Exception {
		InputStream in = null;
		try {
			in = req.getInputStream();
			ByteArrayOutputStream bos = new ByteArrayOutputStream();

			byte[] buff = new byte[BUFF_LENGTH];
			int n;
			while ((n = in.read(buff)) > 0) {
				bos.write(buff, 0, n);
			}

			return bos.toString();
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	private void writeResponse(HttpServletResponse resp) throws Exception {
		resp.addHeader("Content-Type", "application/json");
		resp.setHeader("Content-Length", "" + resp.getBufferSize());

		OutputStream out = null;
		try {
			out = resp.getOutputStream();
			//out.write();
			out.flush();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}
}
